//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//


#ifndef RS_METAFACILITIES_IMPLEMENTATION_INCLUDE_GUARD
#   error "Don't include this file directly! Instead include rs/MetaFacilities.hpp"
#endif

#ifndef RS_METAFACILITIES_IPP
#define RS_METAFACILITIES_IPP

namespace rs
{
    namespace meta
    {
        namespace Internal
        {
            // Idea borrowed from spinxengine
            template< typename T > struct IsTypeTraitObject             { static T &Value; };
            template< typename T > struct IsTypeTraitObject< T& >       { static int Value; };
            template< typename T > struct IsTypeTraitObject< T[] >      { static T Value[]; };
            template< > struct IsTypeTraitObject< void >                { static int Value; };
            template< > struct IsTypeTraitObject< void const >          { static int Value; };
            template< > struct IsTypeTraitObject< void volatile >       { static int Value; };
            template< > struct IsTypeTraitObject< void const volatile > { static int Value; };
            
            
            template< typename T >
            struct AlignmentOfHelper
            {
                T x; char y;
            };
            
            template< bool, typename T > struct IsPolymorphicHelper1 : T { IsPolymorphicHelper1(); virtual ~IsPolymorphicHelper1(); };  
            template< bool, typename T > struct IsPolymorphicHelper2 : T { IsPolymorphicHelper2(); };
            template< typename T > struct IsPolymorphicHelper1< false, T > { };
            template< typename T > struct IsPolymorphicHelper2< false, T > { };
            
            template< typename T > struct IsFundamentalTypeHelper : FalseType { };
            template< > struct IsFundamentalTypeHelper< char > : TrueType { };
            template< > struct IsFundamentalTypeHelper< signed char > : TrueType { };
            template< > struct IsFundamentalTypeHelper< signed short > : TrueType { };
            template< > struct IsFundamentalTypeHelper< signed int > : TrueType { };
            template< > struct IsFundamentalTypeHelper< signed long > : TrueType { };
            template< > struct IsFundamentalTypeHelper< signed long long > : TrueType { };
            template< > struct IsFundamentalTypeHelper< unsigned char > : TrueType { };
            template< > struct IsFundamentalTypeHelper< unsigned short > : TrueType { };
            template< > struct IsFundamentalTypeHelper< unsigned int > : TrueType { };
            template< > struct IsFundamentalTypeHelper< unsigned long > : TrueType { };
            template< > struct IsFundamentalTypeHelper< unsigned long long > : TrueType { };
            template< > struct IsFundamentalTypeHelper< bool > : TrueType { };
            template< > struct IsFundamentalTypeHelper< void > : TrueType { };
            
            template< typename T > struct IsReferenceHelper : FalseType { };
            template< typename T > struct IsReferenceHelper< T& > : TrueType { };
            
            template< typename T > struct IsPointerHelper : FalseType { };
            template< typename T > struct IsPointerHelper< T* > : TrueType { };
            
            enum EnumIsEnumHelper { };
            template< typename T, unsigned > struct IsEnumHelper : FalseType { };
            template< typename T > struct IsEnumHelper< T, sizeof(EnumIsEnumHelper) >
            {
                struct Converter
                {
                    Converter(char);
                    Converter(unsigned char);
                    Converter(signed char);
                    Converter(signed short);
                    Converter(unsigned short);
                    Converter(signed int);
                    Converter(unsigned int);
                    Converter(signed long);
                    Converter(unsigned long);
                    Converter(signed long long);
                    Converter(unsigned long long);
                    Converter(float);
                    Converter(double);
                    Converter(long double);
                };
                
                static char EnumTest(Converter const&);
                static int EnumTest(...);
                
                enum
                {
                    Value = !IsFundamentalType< T >::Result
                         && !IsReference< T >::Result
                         && 1 == sizeof(IsEnumHelper::EnumTest(IsTypeTraitObject< T >::Value))
                };
            };
        }


        //////////////////////////////
        // TypeList & TypeValueList //
        //////////////////////////////
#       if 0
        template< typename THead, typename TTail = void >
        struct TypeList : AbstractMetaList
        {
            typedef THead HeadType;
            typedef TTail TailType;
        };

        template < typename TTypeList >
        struct TypeValueList : AbstractMetaList { };

        template< typename THead, typename TTail >
        struct TypeValueList < TypeList< THead, TTail > > : AbstractMetaList
        {
            typedef THead HeadType;
            typedef TTail TailType;

            TypeValueList(THead head, TypeValueList< TTail > const& tail)
            : head(head),
              tail(tail) {
            }
            
            THead head;
            TypeValueList< TTail > tail;
        };

        template< typename THead, typename TTail >
        struct TypeValueList< TypeList< THead&, TTail > > : AbstractMetaList
        {
            typedef THead HeadType;
            typedef TTail TailType;

        	TypeValueList(THead& head, TypeValueList< TTail > const& tail)
        	: head(head),
        	  tail(tail) {
        	}

            THead head;
        	TypeValueList< TTail > tail;
        };

        template< typename THead, typename TTail >
        struct TypeValueList< TypeList< THead const&, TTail > > : AbstractMetaList
        {
            typedef THead HeadType;
            typedef TTail TailType;

        	TypeValueList(THead const& head, TypeValueList< TTail > const& tail)
        	: head(head),
        	  tail(tail) {
        	}
        	
        	THead head;
        	TypeValueList< TTail > tail;
        };
#       endif
        
        
        ///////////
        // Logic //
        ///////////
        template< bool expression, typename True, typename False > struct If { typedef True Result; };
        template< typename True, typename False > struct If< false, True, False > { typedef False Result; };
        
        template< bool B1, bool B2, bool B3 , bool B4 , bool B5 , bool B6 , bool B7  > struct LogicalAnd : FalseType { };
        template< > struct LogicalAnd< true, true, true, true, true, true, true > : TrueType { };
        
        template< bool B1, bool B2, bool B3, bool B4, bool B5, bool B6, bool B7 > struct LogicalOr : TrueType { };        
        template< > struct LogicalOr< false, false, false, false, false, false, false > : FalseType { };
        
        
        ///////////////////////////////////
        // Type Manipulation & Utilities //
        ///////////////////////////////////
        template< typename T > struct IsPolymorphic :
            LogicalAnd< IsClass< T >::Value, sizeof(Internal::IsPolymorphicHelper1< IsClass< T >::Value, T >) == sizeof(Internal::IsPolymorphicHelper2< IsClass< T >::Value, T >) >
                { };
        
        template< typename T > struct IsClass :
            LogicalAnd< !IsFundamentalType< T >::Value, !IsReference< T >::Value, !IsPointer< T >::Value, !IsArray< T >::Value, !IsEnum< T >::Value >
                { };
                
        template< typename T > struct IsFundamentalType : Internal::IsFundamentalTypeHelper< typename RemoveConstVolatile< T >::Result > { };
        
        template< typename T > struct IsReference : Internal::IsReferenceHelper< typename RemoveConstVolatile< T >::Result > { };        
        
        template< typename T > struct IsPointer : Internal::IsPointerHelper< typename RemoveConstVolatile< T >::Result > { };
        
        template< typename T > struct IsArray : FalseType { };
        template< typename T > struct IsArray< T[] > : TrueType { };
        template< typename T, unsigned size > struct IsArray< T[size] > : TrueType { };
        
        template< typename T > struct IsEnum
        :
        If
        <
            Internal::IsEnumHelper
            <
                T,
                MetaSizeOf
                <
                    typename If
                    <
                        !IsReference< T >::Value,
                        T,
                        char
                    >::Result
                >::Value
            >::Value,
            TrueType,
            FalseType
        >::Result
        { };
        
        template< typename T > struct AddConst { typedef T const Result; };
        template< typename T > struct AddConst< T const > { typedef T const Result; };
        template< typename T > struct AddConst< T volatile > { typedef T const volatile Result; };
        template< typename T > struct AddConst< T const volatile > { typedef T const volatile Result; };
        template < typename T > struct AddConst< T& > { typedef T& Result; };
        
        template< typename T > struct AddVolatile{ typedef T volatile Result; };
        template< typename T > struct AddVolatile< T volatile > { typedef T volatile Result; };
        template< typename T > struct AddVolatile< T const > { typedef T const volatile Result; };
        template< typename T > struct AddVolatile< T const volatile > { typedef T const volatile Result; };
        template < typename T > struct AddVolatile< T& > { typedef T const& Result; };
        
        template< typename T > struct AddConstVolatile{ typedef T const volatile Result; };
        template< typename T > struct AddConstVolatile< T const > { typedef T const volatile Result; };
        template< typename T > struct AddConstVolatile< T volatile > { typedef T const volatile Result; };
        template< typename T > struct AddConstVolatile< T const volatile > { typedef T const volatile Result; };
        template< typename T > struct AddConstVolatile< T& > { typedef T& Result; };
        
        template< typename T > struct AddPointer{ typedef T* Result; };
        template< typename T > struct AddPointer< T& > { typedef T* Result; };
        
        template< typename T > struct AddReference{ typedef T& Result; };
        template< typename T > struct AddReference< T& > { typedef T& Result; };
        
        template< typename T > struct RemoveConst{ typedef T Result; };
        template< typename T > struct RemoveConst< T const > { typedef T Result; };
        template< typename T > struct RemoveConst< T const volatile > { typedef T volatile Result; };
        
        template< typename T > struct RemoveVolatile{ typedef T Result; };
        template< typename T > struct RemoveVolatile< T volatile > { typedef T Result; };
        template< typename T > struct RemoveVolatile< T const volatile > { typedef T const Result; };
        
        template< typename T > struct RemoveConstVolatile{ typedef T Result; };
        template< typename T > struct RemoveConstVolatile< T const > { typedef T Result; };
        template< typename T > struct RemoveConstVolatile< T volatile > { typedef T Result; };
        template< typename T > struct RemoveConstVolatile< T const volatile > { typedef T Result; };
        
        template< typename T > struct RemovePointer{ typedef T Result; };
        template< typename T > struct RemovePointer< T* > { typedef T Result; };
        template< typename T > struct RemovePointer< T* const > { typedef T Result; };
        template< typename T > struct RemovePointer< T* volatile > { typedef T Result; };
        template< typename T > struct RemovePointer< T* const volatile > { typedef T Result; };
        
        template< typename T > struct RemoveReference{ typedef T Result; };
        template< typename T > struct RemoveReference< T& > { typedef T Result; };
        
        
        ///////////////
        // Utilities //
        ///////////////
        template< typename T > struct MetaSizeOf
        {
            enum { Value = sizeof(T) };
        };
        
        template< > struct MetaSizeOf< void >                { enum { Value = 0}; };
        template< > struct MetaSizeOf< void const >          { enum { Value = 0}; };
        template< > struct MetaSizeOf< void volatile >       { enum { Value = 0}; };
        template< > struct MetaSizeOf< void const volatile > { enum { Value = 0}; };
        
        
        template< typename T > struct AlignmentOf { enum { Value = sizeof(Internal::AlignmentOfHelper< T >) - sizeof(T) }; };
        template< > struct AlignmentOf< void >                { enum { Value = 0}; };
        template< > struct AlignmentOf< void const >          { enum { Value = 0}; };
        template< > struct AlignmentOf< void volatile >       { enum { Value = 0}; };
        template< > struct AlignmentOf< void const volatile > { enum { Value = 0}; }; 
    }
}

#endif // RS_METAFACILITIES_IPP
